#include <iostream>
#include <typeinfo>
#include <cassert>
#include <unistd.h>

/*⾸先Any类肯定不能是⼀个模板类，否则编译的时候 Any<int> a,  Any<float>b,需要传类型作为模板参数，也就是说在使⽤的时候就要确定其类型*/
/*这是⾏不通的，因为保存在Content中的协议上下⽂，我们在定义any对象的时候是不知道他们的协议类型的，因此⽆法传递类型作为模板参数*/
/*因此考虑Any内部设计⼀个模板容器holder类，可以保存各种类型数据，但是这样同样需要传递模板参数*/
/*所以，定义⼀个基类placehoder，让holder继承于placeholde，⽽Any类保存⽗类指针即可，固定父类指针指向模板子类*/
/*当需要保存数据时，则new⼀个带有模板参数的⼦类holder对象出来保存数据，然后让Any类中的⽗类指针，指向这个⼦类对象就搞定了*/
class Any
{
private:
    class holder
    {
    public:
        // 析构函数被编译器认为destructor()，在继承关系中如果基类的析构函数不是虚函数，基类与子类的析构函数天然的构成隐藏，
        // 这意味着通过基类指针删除派生类对象时，基类的析构函数对子类来说不可见，只会调用派生类的析构函数，而不会调用基类的析构函数
        virtual ~holder() {}
        virtual const std::type_info &type() = 0;
        virtual holder *clone() = 0;
    };
    template <class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T &val) : _val(val) {}
        // 获取placeholder模板子类对象保存的数据类型，typeid返回模板参数T类型信息
        virtual const std::type_info &type() { return typeid(T); }
        // 针对当前的对象自身_val，克隆出一个新的子类对象
        virtual holder *clone() { return new placeholder(_val); }

    public:
        T _val;
    };
    holder *_content; // ⽽Any类只需要管理holder对象即可

public:
    Any() : _content(NULL) {}
    // 为了能够接收所有类型的对象，因此将构造函数定义为⼀个模板函数
    template <class T>
    Any(const T &val) : _content(new placeholder<T>(val)) {} // 不需要显式地传递模板参数 T，因为它可以从构造函数的参数中推导出来
    Any(const Any &other) : _content(other._content ? other._content->clone() : NULL) {}
    ~Any() { delete _content; }

    Any &swap(Any &other)
    {
        std::swap(_content, other._content);
        return *this;
    }

    // 返回子类对象保存数据的指针，使用模板参数T可以确保编译器知道你想要的数据类型
    template <class T>
    T *get()
    {
        // 想要获取的数据类型，必须和保存的数据类型一致
        assert(typeid(T) == _content->type());
        //_content为holder类型，holder类中并没有_val成员，只有虚成员函数才构成多态，无法识别_content->val
        return &((placeholder<T> *)_content)->_val;
    }

    // 赋值运算符的重载函数：实现任意类型数据对any对象的赋值
    template <class T>
    Any &operator=(const T &val)
    {
        // 为val构造一个临时的通用容器，然后与当前容器自身进行交换，临时对象释放的时候，原先保存的数据也就被释放
        Any(val).swap(*this);
    }

    Any &operator=(const Any &other)
    {
        Any(other).swap(*this);
        return *this;
    }
};

class Test
{
public:
    Test() { std::cout << "构造" << std::endl; }
    Test(const Test &t) { std::cout << "拷贝" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

int main()
{

    Any a;
    {
        Test t;
        a = t;
    }

    // a = 10;
    //  int *pa = a.get<int>();
    //  std::cout << *pa << std::endl;
    //  a = std::string("nihao");
    //  std::string *ps = a.get<std::string>();
    //  std::cout << *ps << std::endl;

    while (1)
        sleep(1);
    return 0;
}
